#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
账号管理模块

这个模块负责管理所有账号的数据和状态。
"""

import os
import json
import time
from PyQt6.QtCore import QObject, pyqtSignal
from logger import get_logger
from account_utils import REQUIRED_FIELDS, OPTIONAL_FIELDS, validate_account, ensure_account_fields

# 获取日志记录器
logger = get_logger(__name__)

# 常量定义
TEMP_DIR = 'temp'
ACCOUNTS_FILE = os.path.join(TEMP_DIR, 'accounts.json')
USER_DATA_ROOT = os.path.join(TEMP_DIR, 'user_data')

class AccountManager(QObject):
    """账号管理类，负责管理所有账号的数据和状态"""

    # 定义信号
    account_added = pyqtSignal(str, dict)  # 账号ID, 账号数据
    account_updated = pyqtSignal(str, dict)  # 账号ID, 更新后的数据
    account_deleted = pyqtSignal(str)  # 账号ID
    account_status_changed = pyqtSignal(str, bool)  # 账号ID, 是否登录

    def __init__(self, parent=None):
        """初始化账号管理器

        Args:
            parent: 父对象
        """
        super().__init__(parent)
        self.accounts = {}  # 使用字典存储账号, port 为键
        # 确保 temp 目录存在
        os.makedirs(TEMP_DIR, exist_ok=True)

        self.accounts_file = ACCOUNTS_FILE
        self.user_data_root = USER_DATA_ROOT
        self.account_loggers = {}  # 存储每个账号的日志记录器
        self.ui_handlers = {}  # 存储每个账号的UI处理器

        # 确保必要的目录存在
        os.makedirs(self.user_data_root, exist_ok=True)

        # 加载账号数据
        self.load_accounts()

    def _get_ui_handler(self, port_str):
        """获取指定账号的UI日志处理器
        
        Args:
            port_str: 账号端口字符串
            
        Returns:
            UIHandler: 配置好的UI日志处理器
        """
        if port_str not in self.ui_handlers:
            handler = UIHandler(port_str)
            self.ui_handlers[port_str] = handler
        return self.ui_handlers[port_str]
        
    def load_accounts(self):
        """从文件加载账号数据. accounts.json 将存储为 {port_str: account_dict} 的格式."""
        self.accounts = {}
        try:
            if os.path.exists(self.accounts_file):
                with open(self.accounts_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    if isinstance(data, list):  # 旧格式是列表
                        logger.info("检测到旧的列表格式 accounts.json, 转换为以 port 为键的字典格式.")
                        for account_data in data:
                            port = account_data.get('port')
                            if port is not None:
                                self.accounts[str(port)] = account_data
                            else:
                                logger.warning(f"账号数据缺少 'port' 字段, 跳过: {account_data.get('nickname')}")
                        self.save_accounts()  # 转换后立即保存为新格式
                    elif isinstance(data, dict):  # 新格式是字典
                        self.accounts = data
                        logger.info(f"从字典格式加载了 {len(self.accounts)} 个账号.")
                    else:
                        logger.warning(f"未知的 accounts.json 文件格式. 初始化为空字典.")
                        self.accounts = {}
            else:
                logger.info("账号文件不存在 (accounts.json). 将创建新的空文件.")
                self.accounts = {}
                self.save_accounts() # 创建空的字典格式文件
        except json.JSONDecodeError as e:
            logger.error(f"解析 accounts.json 失败: {str(e)}. 文件可能已损坏或为空. 初始化为空字典.")
            self.accounts = {}
            # Optionally, attempt to create a new empty file if parsing fails due to emptiness/corruption
            if os.path.exists(self.accounts_file) and os.path.getsize(self.accounts_file) == 0:
                logger.info("accounts.json 为空, 初始化并保存为空字典.")
            elif not os.path.exists(self.accounts_file):
                 logger.info("accounts.json 不存在, 初始化并保存为空字典.")
            self.save_accounts()
        except Exception as e:
            logger.error(f"加载账号数据时发生未知错误: {str(e)}. 初始化为空字典.")
            self.accounts = {}

    def save_accounts(self):
        """保存账号数据到文件 (字典格式, port 为键)"""
        try:
            if not isinstance(self.accounts, dict):
                logger.error(f"尝试保存非字典类型的账号数据: {type(self.accounts)}. 将尝试转换或重置.")
                if isinstance(self.accounts, list):
                    temp_accounts_dict = {}
                    for acc_data in self.accounts:
                        port = acc_data.get('port')
                        if port is not None:
                            temp_accounts_dict[str(port)] = acc_data
                    self.accounts = temp_accounts_dict
                    logger.info("已将列表格式的 self.accounts 转换为字典格式进行保存.")
                else:
                    self.accounts = {}
                    logger.warning("self.accounts 重置为空字典.")
            # 保存前处理每个账号数据
            for port_str, account_data in self.accounts.items():
                account_data = ensure_account_fields(account_data)
                if 'port' not in account_data or account_data['port'] != int(port_str):
                    account_data['port'] = int(port_str)
                # 只在登录且 nickname 非空时写入 nickname 字段，否则移除
                if not account_data.get('is_logged', False) or not account_data.get('nickname', ''):
                    account_data.pop('nickname', None)
                else:
                    pass  # 已有 nickname 字段且有效
                self.accounts[port_str] = account_data
            with open(self.accounts_file, 'w', encoding='utf-8') as f:
                json.dump(self.accounts, f, ensure_ascii=False, indent=2)
            logger.info(f"账号数据成功保存到 {self.accounts_file} ({len(self.accounts)} 个账号)")
            return True
        except Exception as e:
            logger.error(f"保存账号数据失败: {str(e)}")
            return False




    def find_available_port(self, start_port=9222):
        """查找可用的端口号

        Args:
            start_port: 起始端口号

        Returns:
            int: 可用的端口号
        """
        # self.accounts 的键是字符串形式的端口号
        used_ports = {int(p_str) for p_str in self.accounts.keys()}
        port = start_port
        while port in used_ports:
            port += 1
        return port



    def add_account(self, account_data):
        """添加或更新账号. 使用 account_data 中的 'port' 作为键.

        Args:
            account_data: 账号数据字典, 必须包含 'port'.

        Returns:
            bool: 是否操作成功
        """
        try:
            port = account_data.get('port')
            if port is None:
                port = self.find_available_port()
                account_data['port'] = port
                logger.info(f"为新账号分配了端口: {port}")
            port_str = str(port)
            account_data['port'] = int(port)
            if 'account_id' in account_data:
                del account_data['account_id']

            # 仅在登录且有真实昵称时才保存 nickname 字段
            is_logged = account_data.get('is_logged', False)
            nickname = account_data.get('nickname', '')
            final_account_data = ensure_account_fields(account_data)
            if not (is_logged and nickname):
                final_account_data.pop('nickname', None)
            is_new_account = port_str not in self.accounts
            action_type = '添加' if is_new_account else '更新'
            self.accounts[port_str] = final_account_data
            
            # 为账号创建专用日志记录器
            if port_str not in self.account_loggers:
                self.account_loggers[port_str] = get_logger(f"account_{port_str}", account_id=port_str)
                # 将日志记录器与账号UI界面关联
                self.account_loggers[port_str].ui_handler = self._get_ui_handler(port_str)
            
            logger.info(f"账号数据已在内存中为端口 {port_str} {action_type}.")
            if self.save_accounts():
                if is_new_account:
                    self.account_added.emit(port_str, final_account_data)
                    logger.info(f"成功添加新账号 (端口: {port_str}).")
                else:
                    self.account_updated.emit(port_str, final_account_data)
                    logger.info(f"成功更新账号 (端口: {port_str}).")
                return True
            else:
                logger.error(f"为端口 {port_str} 保存账号数据到文件失败.")
                return False
        except Exception as e:
            logger.error(f"添加/更新账号 (端口: {account_data.get('port')}) 时发生错误: {str(e)}")
            return False

    def update_account(self, port, update_data):
        """更新指定端口的账号信息.

        Args:
            port: 账号的端口号 (int).
            update_data: 要更新的数据字典.

        Returns:
            bool: 是否更新成功.
        """
        port_str = str(port)
        try:
            if port_str in self.accounts:
                # 更新数据，确保 port 字段不被错误覆盖或删除
                # port 字段本身不应该通过此方法修改，它是键
                if 'port' in update_data and update_data['port'] != int(port_str):
                    logger.warning(f"尝试通过 update_account 修改端口 {port_str} 的 'port' 字段为 {update_data['port']}. 此操作被忽略.")
                    del update_data['port'] # 不允许通过此方法修改 port 字段本身
                
                self.accounts[port_str].update(update_data)
                # 确保更新后，账号数据中的 port 字段仍为正确的整数值
                self.accounts[port_str]['port'] = int(port_str)
                
                logger.info(f"账号 (端口: {port_str}) 的信息已在内存中更新: {update_data}")
                
                if self.save_accounts():
                    self.account_updated.emit(port_str, self.accounts[port_str])
                    logger.info(f"成功更新并保存账号 (端口: {port_str}).")
                    return True
                else:
                    logger.error(f"为端口 {port_str} 保存更新后的账号数据到文件失败.")
                    # 考虑是否回滚内存中的更新
                    return False
            else:
                logger.warning(f"未找到端口为 {port_str} 的账号，无法更新. 如果要添加新账号，请使用 add_account.")
                return False
        except Exception as e:
            logger.error(f"更新账号 (端口: {port_str}) 失败: {str(e)}")
            return False

    def delete_account(self, port):
        """删除指定端口的账号.

        Args:
            port: 账号的端口号 (int).

        Returns:
            bool: 是否删除成功.
        """
        port_str = str(port)
        try:
            if port_str in self.accounts:
                deleted_account_data = self.accounts.pop(port_str)
                logger.info(f"账号 (端口: {port_str}) 已从内存中删除.")
                
                # 删除关联的用户数据目录
                user_data_dir_to_remove = os.path.join(self.user_data_root, f"port_{port_str}")
                if os.path.exists(user_data_dir_to_remove):
                    try:
                        import shutil
                        shutil.rmtree(user_data_dir_to_remove)
                        logger.info(f"已删除用户数据目录: {user_data_dir_to_remove}")
                    except Exception as e_rm:
                        logger.error(f"删除用户数据目录 {user_data_dir_to_remove} 失败: {e_rm}")
                else:
                    logger.info(f"用户数据目录 {user_data_dir_to_remove} 不存在，无需删除.")

                if self.save_accounts():
                    self.account_deleted.emit(port_str)
                    logger.info(f"成功删除并保存账号 (端口: {port_str}).")
                    return True
                else:
                    logger.error(f"为端口 {port_str} 保存删除后的账号列表到文件失败.")
                    self.accounts[port_str] = deleted_account_data # 回滚内存中的删除操作
                    return False
            else:
                logger.warning(f"未找到端口为 {port_str} 的账号，无法删除.")
                return False
        except Exception as e:
            logger.error(f"删除账号 (端口: {port_str}) 失败: {str(e)}")
            return False

    def get_account(self, port):
        """获取指定端口的账号信息.

        Args:
            port: 账号的端口号 (int).

        Returns:
            dict: 账号数据字典，如果账号不存在则返回None.
        """
        port_str = str(port)
        account_data = self.accounts.get(port_str)
        if account_data:
            logger.debug(f"找到端口为 {port_str} 的账号.")
        else:
            logger.debug(f"未找到端口为 {port_str} 的账号.")
        return account_data

    def get_all_accounts(self):
        """获取所有账号信息 (以列表形式返回).

        Returns:
            list: 所有账号数据字典的列表.
        """
        return list(self.accounts.values())

    def update_account_status(self, port, is_logged):
        """更新指定端口账号的登录状态.

        Args:
            port: 账号的端口号 (int).
            is_logged: 是否已登录 (bool).

        Returns:
            bool: 是否更新成功.
        """
        port_str = str(port)
        try:
            if port_str in self.accounts:
                self.accounts[port_str]['is_logged'] = is_logged
                logger.info(f"账号 (端口: {port_str}) 的登录状态已在内存中更新为: {is_logged}")
                if self.save_accounts():
                    self.account_status_changed.emit(port_str, is_logged)
                    logger.info(f"成功更新并保存账号 (端口: {port_str}) 的登录状态.")
                    return True
                else:
                    logger.error(f"为端口 {port_str} 保存更新后的登录状态到文件失败.")
                    # Consider reverting in-memory update
                    return False
            else:
                logger.warning(f"未找到端口为 {port_str} 的账号，无法更新登录状态.")
                return False
        except Exception as e:
            logger.error(f"更新账号 (端口: {port_str}) 登录状态失败: {str(e)}")
            return False

    def get_logged_accounts(self):
        """获取所有已登录的账号 (以列表形式返回).

        Returns:
            list: 已登录账号的数据字典的列表.
        """
        return [account_data for account_data in self.accounts.values() if account_data.get('is_logged', False)]

    def get_available_port(self):
        """获取可用的端口号

        Returns:
            int: 可用的端口号
        """
        return self.find_available_port()